import { createApp, Directive } from "vue";
import "./style.css";
import App from "./App.vue";
import router from "./router";

const app = createApp(App);

// 动画持续时间，ms
const DURATION = 300;

/**
 * @description 基于Vue3自定义指令的数字递增动画效果
 *
 * @example     `<div v-increase="100"></div>`
 */
const increase: Directive = {
  // 在绑定元素的父组件
  // 及他自己的所有子节点都挂载完成后调用
  mounted(el, binding) {
    const { value: maxCount } = binding;
    el.$animation = animate((progress) => {
      el.innerText = Math.floor(maxCount * progress);
    }, DURATION);
  },
  beforeUpdate(el, binding) {
    const { value: maxCount, oldValue: oldMaxCount } = binding;
    el.$animation = animate((progress) => {
      el.innerText =
        oldMaxCount + Math.floor((maxCount - oldMaxCount) * progress);
    }, DURATION);
  },
  // 绑定元素的父组件卸载后调用
  unmounted(el) {
    el.$animation.cancel();
  },
};

/**
 * @description             基于requestAnimationFrame，实现在持续时间内执行动画的方法
 *
 * @param fn                动画执行函数，参数progress表示完成的进度
 * @param duration          动画持续时间
 * @returns {object.cancel} 取消动画
 */
const animate = function (fn: (progress: number) => void, duration: number) {
  const animate = () => {
    animation = requestAnimationFrame(animate);

    const now = new Date().getTime();
    const progress = Math.floor(((now - START) / duration) * 100) / 100;
    fn(progress > 1 ? 1 : progress);
    // 到达持续时间，结束动画
    if (now - START > duration) {
      cancel();
    }
  };

  const cancel = () => {
    cancelAnimationFrame(animation);
  };

  const START = new Date().getTime();

  let animation = requestAnimationFrame(animate);
  return {
    cancel: () => {
      cancelAnimationFrame(animation);
    },
  };
};

app.use(router);
app.directive("increase", increase);
app.mount("#app");
